<template>
  <view v-if="show" class="tn-tabbar-class tn-tabbar" @touchmove.stop.prevent="() => {}">
    <!-- tabbar 内容-->
    <view
      class="tn-tabbar__content"
      :class="{
        'tn-tabbar--fixed': fixed,
        'tn-safe-area-inset-bottom': safeAreaInsetBottom,
        'tn-tabbar--shadow': shadow,
      }"
      :style="{
        height: height + 'rpx',
        backgroundColor: bgColor,
      }"
    >
      <!-- tabbar item -->
      <view
        v-for="(item, index) in list"
        :key="index"
        class="tn-tabbar__content__item"
        :id="`tabbar_item_${index}`"
        :class="{ 'tn-tabbar__content__item--out': item.out }"
        :style="{
          backgroundColor: bgColor,
        }"
        @tap.stop="clickItemHandler(index)"
      >
        <!-- tabbar item的图片或者icon-->
        <view :class="[itemButtonClass(index)]" :style="[itemButtonStyle(index)]">
          <image
            v-if="isImage(index)"
            :src="elIcon(index)"
            mode="scaleToFill"
            class="tn-tabbar__content__item__image"
            :style="{
              width: `${item.iconSize || iconSize}rpx`,
              height: `${item.iconSize || iconSize}rpx`,
            }"
          ></image>
          <view
            v-else
            class="tn-tabbar__content__item__icon"
            :class="[`tn-icon-${elIcon(index)}`, elIconColor(index, false)]"
            :style="{
              fontSize: `${item.iconSize || iconSize}rpx`,
              color: elIconColor(index),
            }"
          ></view>

          <!-- 角标-->
          <tn-badge
            v-if="!item.out && (item.count || item.dot)"
            :dot="item.dot || false"
            backgroundColor="tn-bg-red"
            fontColor="#FFFFFF"
            :radius="item.dot ? 14 : 0"
            :fontSize="14"
            padding="2rpx 4rpx"
            :absolute="true"
            :top="2"
          >
            {{ $tn.number.formatNumberString(item.count) }}
          </tn-badge>
        </view>

        <!-- tabbar item的文字-->
        <view
          class="tn-tabbar__content__item__text"
          :class="[elColor(index, false)]"
          :style="{
            color: elColor(index),
            fontSize: `${fontSize}rpx`,
          }"
        >
          <text class="tn-text-ellipsis">{{ item.title }}</text>
        </view>
      </view>

      <!-- item 突起部分 -->
      <view
        v-if="outItemIndex !== -1"
        class="tn-tabbar__content__out"
        :class="[
          {
            'tn-tabbar__content__out--shadow': shadow,
          },
          animation && value === outItemIndex
            ? `tn-tabbar__content__out--animation--${animationMode}`
            : '',
        ]"
        :style="{
          backgroundColor: bgColor,
          left: outItemLeft,
          width: `${outHeight}rpx`,
          height: `${outHeight}rpx`,
          top: `-${outHeight * 0.3}rpx`,
        }"
        @tap.stop="clickItemHandler(outItemIndex)"
      ></view>
    </view>

    <!-- 防止tabbar塌陷 -->
    <view
      class="tn-tabbar__placeholder"
      :class="{ 'tn-safe-area-inset-bottom': safeAreaInsetBottom }"
      :style="{
        height: `calc(${height}rpx)`,
      }"
    ></view>
  </view>
</template>

<script>
export default {
  name: 'tn-tabbar',
  props: {
    // 绑定当前被选中的current值
    value: {
      type: [String, Number],
      default: 0,
    },
    // 是否显示
    show: {
      type: Boolean,
      default: true,
    },
    // 图标列表
    list: {
      type: Array,
      default() {
        return [];
      },
    },
    // 高度，单位rpx
    height: {
      type: Number,
      default: 100,
    },
    // 突起的高度
    outHeight: {
      type: Number,
      default: 100,
    },
    // 背景颜色
    bgColor: {
      type: String,
      default: '#FFFFFF',
    },
    // 图标大小
    iconSize: {
      type: Number,
      default: 40,
    },
    // 字体大小
    fontSize: {
      type: Number,
      default: 24,
    },
    // 激活时的颜色
    activeColor: {
      type: String,
      default: '#0079fe',
    },
    // 非激活时的颜色
    inactiveColor: {
      type: String,
      default: '#AAAAAA',
    },
    // 激活时图标的颜色
    activeIconColor: {
      type: String,
      default: '#0079fe',
    },
    // 非激活时图标的颜色
    inactiveIconColor: {
      type: String,
      default: '#AAAAAA',
    },
    // 激活时的自定义样式
    activeStyle: {
      type: Object,
      default() {
        return {};
      },
    },
    // 是否显示阴影
    shadow: {
      type: Boolean,
      default: true,
    },
    // 点击时是否有动画
    animation: {
      type: Boolean,
      default: false,
    },
    // 点击时的动画模式
    animationMode: {
      type: String,
      default: 'scale',
    },
    // 是否固定在底部
    fixed: {
      type: Boolean,
      default: true,
    },
    // 是否开启底部安全区适配，开启的话，会在iPhoneX机型底部添加一定的内边距
    safeAreaInsetBottom: {
      type: Boolean,
      default: false,
    },
    // 切换前回调
    beforeSwitch: {
      type: Function,
      default: null,
    },
  },
  computed: {
    // 当前字体的颜色
    elColor() {
      return (index, style = true) => {
        let currentItem = this.list[index];
        let color = '';
        if (index === this.value) {
          color = currentItem['activeColor'] || this.activeColor;
        } else {
          color = currentItem['inactiveColor'] || this.inactiveColor;
        }
        // 判断是否获取内部样式
        if (style) {
          if (this.$tn.color.getFontColorStyle(color) !== '') {
            return color;
          } else {
            return '';
          }
        } else {
          if (this.$tn.color.getFontColorStyle(color) === '') {
            return color;
          } else {
            return '';
          }
        }
      };
    },
    // 当前图标的颜色
    elIconColor() {
      return (index, style = true) => {
        let currentItem = this.list[index];
        let color = '';
        if (index === this.value) {
          color = currentItem['activeIconColor'] || this.activeIconColor;
        } else {
          color = currentItem['inactiveIconColor'] || this.inactiveIconColor;
        }
        // 判断是否获取内部样式
        if (style) {
          if (this.$tn.color.getFontColorStyle(color) !== '') {
            return color;
          } else {
            return '';
          }
        } else {
          if (this.$tn.color.getFontColorStyle(color) === '') {
            return color + ' tn-tabbar__content__item__icon--clip';
          } else {
            return '';
          }
        }
      };
    },
    // 当前的图标
    elIcon() {
      return (index) => {
        let currentItem = this.list[index];
        if (index === this.value) {
          return currentItem['activeIcon'];
        } else {
          return currentItem['inactiveIcon'];
        }
      };
    },
    // 突起部分item button对应的类
    itemButtonClass() {
      return (index) => {
        let clazz = '';
        if (this.list[index]['out']) {
          clazz += 'tn-tabbar__content__item__button--out';
          if (this.$tn.color.getFontColorStyle(this.activeIconColor) === '') {
            clazz += ` ${this.activeIconColor}`;
          }
          if (this.value === index) {
            clazz += ` tn-tabbar__content__item__button--out--animation--${this.animationMode}`;
          }
        } else {
          clazz += 'tn-tabbar__content__item__button';
          if (this.value === index) {
            clazz += ` tn-tabbar__content__item__button--animation--${this.animationMode}`;
          }
        }
        return clazz;
      };
    },
    // 突起部分item button样式
    itemButtonStyle() {
      return (index) => {
        let style = {};
        if (this.list[index]['out']) {
          if (this.$tn.color.getFontColorStyle(this.activeIconColor) !== '') {
            style.backgroundColor = this.activeIconColor;
          }
          style.width = `${this.outHeight - 35}rpx`;
          style.height = `${this.outHeight - 35}rpx`;
          style.top = `-${this.outHeight * 0.15}rpx`;

          return style;
        }
        return style;
      };
    },
    // 判断图标是否为图片
    isImage() {
      return (index) => {
        const icon = this.list[index]['activeIcon'];
        // 只有包含了'/'就认为是图片
        return icon.indexOf('/') !== -1;
      };
    },
  },
  data() {
    return {
      // 当前突起的位置
      outItemLeft: '50%',
      // 当前设置了突起按钮的index
      outItemIndex: -1,
      // 每一个item的信息
      tabbatItemInfo: [],
    };
  },
  watch: {},
  created() {
    this.getOutItemIndex();
  },
  mounted() {
    this.$nextTick(() => {
      this.getTabbarItem();
    });
  },
  methods: {
    // 获取每一个item的信息
    getTabbarItem() {
      let query = uni.createSelectorQuery().in(this);
      // 遍历获取信息
      for (let i = 0; i < this.list.length; i++) {
        query.select(`#tabbar_item_${i}`).fields({
          size: true,
          rect: true,
        });
      }
      query.exec((res) => {
        if (!res) {
          setTimeout(() => {
            this.getTabbarItem();
          }, 10);
          return;
        }
        this.tabbatItemInfo = res.map((item) => {
          return {
            left: item.left,
            width: item.width,
          };
        });
        this.updateOutItemLeft();
      });
    },
    // 获取突起Item所在的index(如果存在)
    getOutItemIndex() {
      this.outItemIndex = this.list.findIndex((item) => {
        return item.hasOwnProperty('out') && item.out;
      });
    },
    // 点击底部菜单时触发
    async clickItemHandler(index) {
      if (this.beforeSwitch && typeof this.beforeSwitch === 'function') {
        // 执行回调，同时传入索引当作参数
        // 在微信，支付宝等环境(H5正常)，会导致父组件定义的函数体中的this变成子组件的this
        // 通过bind()方法，绑定父组件的this，让this的this为父组件的上下文
        let beforeSwitch = this.beforeSwitch.bind(this.$tn.$parent.call(this))(index);
        // 判断是否返回了Promise
        if (!!beforeSwitch && typeof beforeSwitch.then === 'function') {
          await beforeSwitch
            .then((res) => {
              // Promise返回成功
              this.switchTab(index);
            })
            .catch((err) => {});
        } else if (beforeSwitch === true) {
          this.switchTab(index);
        }
      } else {
        this.switchTab(index);
      }
    },
    // 切换tab
    switchTab(index) {
      // 发出事件和修改v-model绑定的值
      this.$emit('change', index);
      this.$emit('input', index);
    },
    // 设置突起的位置
    updateOutItemLeft() {
      // 查找出需要突起的元素
      const index = this.list.findIndex((item) => {
        return item.out;
      });
      if (index !== -1) {
        this.outItemLeft =
          this.tabbatItemInfo[index].left + this.tabbatItemInfo[index].width / 2 + 'px';
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.tn-tabbar {
  &__content {
    box-sizing: content-box;
    display: flex;
    flex-direction: row;
    align-items: center;
    position: relative;
    width: 100%;
    z-index: 1024;

    &__out {
      position: absolute;
      z-index: 4;
      border-radius: 100%;
      left: 50%;
      transform: translateX(-50%);

      &--shadow {
        box-shadow: 0rpx -10rpx 30rpx 0rpx rgba(0, 0, 0, 0.05);

        &::before {
          content: ' ';
          position: absolute;
          width: 100%;
          height: 50rpx;
          bottom: 0;
          left: 0;
          right: 0;
          margin: auto;
          background-color: inherit;
        }
      }

      &--animation {
        &--scale {
          transform-origin: 50% 100%;
          animation: tabbar-content-out-click 0.2s forwards 1 ease-in-out;
        }
      }
    }

    &__item {
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
      align-items: center;
      height: 100%;
      position: relative;

      &__button {
        margin-bottom: 10rpx;
        display: flex;
        align-items: center;
        justify-content: center;
        position: relative;

        &--out {
          margin-bottom: 10rpx;
          border-radius: 50%;
          position: absolute;
          display: flex;
          justify-content: center;
          align-items: center;
          z-index: 6;

          &--animation {
            &--scale {
              transform-origin: 50% 100%;
              animation: tabbar-item-button-out-click 0.2s forwards 1;
            }
          }
        }

        &--animation {
          &--scale {
            .tn-tabbar__content__item__icon,
            .tn-tabbar__content__item__image {
              transform-origin: 50% 100%;
              animation: tabbar-item-button-click 0.2s forwards 1;
            }
          }
        }
      }

      &__icon {
        &--clip {
          -webkit-background-clip: text;
          color: transparent !important;
        }
      }

      &__text {
        width: 100%;
        font-size: 26rpx;
        line-height: 28rpx;
        text-align: center;
        margin-bottom: 10rpx;
        z-index: 10;
        transition: all 0.2s ease-in-out;
      }

      &--out {
        height: calc(100% - 1px);
      }
    }
  }

  &--fixed {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
  }

  &--shadow {
    box-shadow: 0rpx 0rpx 30rpx 0rpx rgba(0, 0, 0, 0.07);
  }
}

/* 点击动画 start */

@keyframes tabbar-item-button-click {
  from {
    transform: scale(0.8);
  }
  to {
    transform: scale(1);
  }
}

@keyframes tabbar-item-button-out-click {
  0% {
    transform: translateY(0) scale(1);
  }
  50% {
    transform: translateY(-10rpx) scale(1.2);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}

@keyframes tabbar-content-out-click {
  0% {
    transform: translateX(-50%) translateY(0) scale(1);
  }
  50% {
    transform: translateX(-50%) translateY(-10rpx) scale(1.1);
  }
  100% {
    transform: translateX(-50%) translateY(0) scale(1);
  }
}

/* 点击动画 end */
</style>
